﻿using Clirelmgt.Manager;
using Clirelmgt.Models;
using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web;
using System.Web.Mvc;

namespace Clirelmgt.Controllers
{
    public class PageController : Controller
    {
        public Dictionary<string, object> ContextData { get; set; }

        private static string serverPath;

        public ActionResult Card(string ID, string mode, string key)
        {
            if (Session["crmsession"] == null)
            {
                return RedirectToAction("Login", "Account");
            }

            string langid = Utility.GetLanguage(Session["crmsession"]);
            bool isnew = true;
            ContextData = new Dictionary<string, object>();
            if (Request.QueryString.AllKeys.Count() > 0)
            {
                if (mode.ToLowerInvariant() == "edit")
                {
                    isnew = false;
                    ViewBag.No = key;
                    ViewBag.SubmitBtn = "Update";
                }
                else
                {
                    isnew = true;
                    ViewBag.No = "NEW";
                    ViewBag.SubmitBtn = "Save";
                }
            }
            else
            {
                isnew = true;
                ViewBag.No = "NEW";
                ViewBag.SubmitBtn = "Save";
            }

            MetaCardPage cardPage = new MetaCardPage();
            using (CRMDataContext dataContext = new CRMDataContext())
            {
                var appObjects = dataContext.GetAppObject(ID, "CARD", true);
                foreach (var appObject in appObjects)
                {
                    string formXml = appObject.AppMetaData;
                    cardPage = Utility.DeserializeString<MetaCardPage>(formXml) as MetaCardPage;
                    string tableName = appObject.LinkTable;
                    MetaTable tableMetadata = Utility.DeserializeString<MetaTable>(appObject.TableMetadata) as MetaTable;
                    cardPage.PrefixKey = tableMetadata.PrefixKey;
                    foreach (MetaFieldGroup fieldGroup in cardPage.FieldGroups)
                    {
                        foreach (MetaFormField field in fieldGroup.Fields)
                        {
                            MetaTableField tableField = tableMetadata.Fields.Where(obj => (obj.Name == field.Name)).ToList()[0];
                            List<MetaLanguage> languageLables = tableField.Labels.Where(obj => (obj.LangID == langid)).ToList();
                            if (languageLables.Count > 0)
                            {
                                field.DisplayLabel = languageLables[0].LabelText;
                            }
                            field.DataType = tableField.DataType;
                            field.FieldLength = tableField.FieldLength;
                            field.Required = tableField.NotNull;
                            if (field.DataType == FieldDataType.Select)
                            {
                                field.Options = tableField.Options;
                            }
                            else if (field.DataType == FieldDataType.Table)
                            {
                                field.Options = tableField.Options;
                            }

                            ContextData.Add(field.Name, field.FieldValue);
                        }
                    }

                    if (!isnew)
                    {
                        string selectQuery = DataHelper.GetSqlSelectStatement(tableName, ContextData, string.Format("[No]='{0}'", key));
                        DataSet resultSet = DataAccess.RunSelectStatement(selectQuery);
                        if (resultSet.Tables.Count > 0)
                        {
                            if (resultSet.Tables[0].Rows.Count > 0)
                            {
                                DataRow record = resultSet.Tables[0].Rows[0];
                                foreach (MetaFieldGroup fieldGroup in cardPage.FieldGroups)
                                {
                                    foreach (MetaFormField field in fieldGroup.Fields)
                                    {
                                        if (field.DataType == FieldDataType.Bool)
                                        {
                                            if (record[field.Name].ToString() == "true")
                                            {
                                                field.FieldValue = "on";
                                            }
                                            else
                                            {
                                                field.FieldValue = "off";
                                            }
                                        }
                                        else if (field.DataType == FieldDataType.Date)
                                        {
                                            if (!string.IsNullOrWhiteSpace(record[field.Name].ToString()))
                                            {
                                                field.FieldValue = Convert.ToDateTime(record[field.Name]).ToString("yyyy-MM-dd");
                                            }
                                        }
                                        else
                                        {
                                            field.FieldValue = record[field.Name].ToString();
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (TempData.ContainsKey("CardPage"))
                    {
                        TempData["CardPage"] = cardPage;
                    }
                    else
                    {
                        TempData.Add("CardPage", cardPage);
                    }
                }
            }

            return View(cardPage);
        }

        [HttpPost]
        public ActionResult Card(string ID, string mode, string key, FormCollection formData)
        {
            if (Session["crmsession"] == null)
            {
                return RedirectToAction("Login", "Account");
            }

            string userId = Utility.GetUserId(Session["crmsession"]);
            string langid = Utility.GetLanguage(Session["crmsession"]);
            bool isnew = true;
            ContextData = new Dictionary<string, object>();
            if (Request.QueryString.AllKeys.Count() > 0)
            {
                if (mode.ToLowerInvariant() == "edit")
                {
                    isnew = false;
                    ViewBag.No = key;
                    ViewBag.SubmitBtn = "Update";
                }
                else
                {
                    isnew = true;
                    ViewBag.No = "NEW";
                    ViewBag.SubmitBtn = "Save";
                }
            }
            else
            {
                isnew = true;
                ViewBag.No = "NEW";
                ViewBag.SubmitBtn = "Save";
            }

            MetaCardPage cardPage = new MetaCardPage();
            cardPage = TempData["CardPage"] as MetaCardPage;
            using (CRMDataContext dataContext = new CRMDataContext())
            {
                foreach (MetaFieldGroup fieldGroup in cardPage.FieldGroups)
                {
                    foreach (MetaFormField field in fieldGroup.Fields)
                    {
                        if (Request.Form.AllKeys.Contains(field.Name))
                        {
                            if (field.DataType == FieldDataType.Bool)
                            {
                                string value = "false";
                                if (Request.Form[field.Name] == "on")
                                {
                                    value = "true";
                                }

                                field.FieldValue = value;
                            }
                            else
                            {
                                field.FieldValue = Request.Form[field.Name];
                            }

                            ContextData.Add(field.Name, field.FieldValue);
                        }
                    }
                }

                if (isnew)
                {
                    string insertQuery = DataHelper.GetSqlInsertStatement(cardPage.LinkTable, cardPage.PrefixKey, ContextData, userId);
                    DataAccess.ExecuteNonQuery(insertQuery);
                }
                else
                {
                    string updateQuery = DataHelper.GetSqlUpdateStatement(cardPage.LinkTable, ContextData, string.Format("[No]='{0}'", key), userId);
                    DataAccess.ExecuteNonQuery(updateQuery);
                }

                if (TempData.ContainsKey("CardPage"))
                {
                    TempData["CardPage"] = cardPage;
                }
                else
                {
                    TempData.Add("CardPage", cardPage);
                }
            }

            return View(cardPage);
        }

        private string RunCustCode(string method)
        {
            string result = "";
            //Assembly funcLib = Assembly.LoadFile(@"E:\codeplex\FlexiMax\DynamicForm\DynamicForm\bin\DynoFuncLibrary.dll");
            //Type type = funcLib.GetType("DynoFuncLibrary");
            //if (type != null)
            //{
            //    MethodInfo methodInfo = type.GetMethod(method.Replace("FuncLib@", ""));
            //    if (methodInfo != null)
            //    {
            //        List<object> parameters = new List<object>();
            //        parameters.Add(ContextData);
            //        methodInfo.Invoke(methodInfo, parameters.ToArray());
            //    }
            //}

            //string[] splitStr = method.Split('.');

            //using (DynoDataContext dataContext = new DynoDataContext())
            //{
            //    List<AppObject> appObjects = dataContext.AppObjects.Where(obj => (obj.Name == splitStr[0] && obj.PageType == "CLASS")).ToList();
            //    if (appObjects.Count > 0)
            //    {
            //        string formXml = appObjects[0].Metadata;
            //        DynoClass dynoClass = Utility.DeserializeString<DynoClass>(formXml) as DynoClass;
            //        List<DynoClassMethod> methods = dynoClass.Method.Where(obj => (obj.Name == splitStr[1])).ToList();
            //        if (methods.Count > 0)
            //        {
            //            StringBuilder snippet = new StringBuilder();

            //            snippet.AppendLine(string.Format("public class Cls{0}", appObjects[0].Name));
            //            snippet.AppendLine("{");
            //            snippet.AppendLine(string.Format("    public static {0} {1}(Dictionary<string, string> ContextData)", methods[0].OutputVariable.DataType, methods[0].Name));
            //            snippet.AppendLine("    {");
            //            if (methods[0].OutputVariable != null)
            //            {
            //                snippet.AppendLine(string.Format("{0} {1};", methods[0].OutputVariable.DataType, methods[0].OutputVariable.Name));
            //            }

            //            snippet.AppendLine(methods[0].CodeExec);
            //            snippet.AppendLine("    }");
            //            snippet.AppendLine("}");

            //            CompilerResults cresult = CompileScript(snippet.ToString());
            //        }
            //    }
            //}

            return result;
        }

        public ActionResult List(string ID)
        {
            if (Session["crmsession"] == null)
            {
                return RedirectToAction("Login", "Account");
            }

            string pageName = ID;
            string langId = Utility.GetLanguage(Session["crmsession"]);

            MetaListPage listPage = new MetaListPage();
            ListModel model = new ListModel();
            using (CRMDataContext dataContext = new CRMDataContext())
            {
                var appObjects = dataContext.GetAppObject(pageName, "LIST", true);
                foreach (var appObject in appObjects)
                {
                    string formXml = appObject.AppMetaData;
                    listPage = Utility.DeserializeString<MetaListPage>(formXml) as MetaListPage;
                    string tableXml = appObject.TableMetadata;
                    string tableName = appObject.LinkTable;
                    MetaTable tableMetadata = Utility.DeserializeString<MetaTable>(tableXml) as MetaTable;
                    model.DisplayFields = new Dictionary<string, string>();
                    foreach (MetaFormField field in listPage.Fields)
                    {
                        string displayName = field.Name;

                        List<MetaTableField> tableFields = tableMetadata.Fields.Where(obj => (obj.Name == field.Name)).ToList();
                        if (tableFields.Count > 0)
                        {
                            List<MetaLanguage> langs = tableFields[0].Labels.Where(obj => (obj.LangID == langId)).ToList();
                            if (langs.Count > 0)
                            {
                                displayName = langs[0].LabelText;
                            }
                        }

                        model.DisplayFields.Add(field.Name, displayName);
                    }

                    model.TableFields = tableMetadata.Fields.ToList();
                    model.Menus = listPage.Menus;
                    model.CardName = listPage.CardPage;
                    string selectQuery = DataHelper.GetSqlSelectStatement(tableName, listPage);
                    DataSet resultSet = DataAccess.RunSelectStatement(selectQuery);
                    if (resultSet != null)
                    {
                        if (resultSet.Tables.Count > 0)
                        {
                            model.RecordTable = resultSet.Tables[0];
                        }
                    }

                    model.Title = string.Format("List of {0}", listPage.Name.ToLowerInvariant());
                }
            }

            if (TempData["model"] == null)
            {
                TempData.Add("model", model);
            }
            else
            {
                TempData["model"] = model;
            }
            return View(model);
        }

        [HttpPost]
        public ActionResult Process(string ID, string Table, string Key, FormCollection form)
        {
            serverPath = Server.MapPath("~/bin");
            if (Session["crmsession"] == null)
            {
                return RedirectToAction("Login", "Account");
            }

            string langid = Utility.GetLanguage(Session["crmsession"]);
            string userId = Utility.GetUserId(Session["crmsession"]);
            ContextData = new Dictionary<string, object>();

            MetaProcessPage cardPage = TempData["ProcPage"] as MetaProcessPage;

            foreach (MetaProcessFieldGroup fieldGroup in cardPage.FieldGroups)
            {
                foreach (MetaProcessField field in fieldGroup.Fields)
                {
                    ContextData.Add(field.Name, form[field.Name]);
                    field.FieldValue = form[field.Name];
                }
            }

            List<string> buttonClicks = form.AllKeys.Where(obj => (obj.Contains("btn_"))).ToList();
            foreach (string buttonClick in buttonClicks)
            {
                string methodName = cardPage.Buttons.Where(obj => (obj.Name == buttonClick.Replace("btn_", ""))).ToList()[0].MethodCall;
                List<MetaScript> loadScripts = cardPage.GlobalScripts.Where(obj => (obj.Name.ToLower() == methodName.ToLower() && obj.Type == ScriptType.Server)).ToList();
                if (loadScripts.Count > 0)
                {
                    RunProcessActionCode(ID, loadScripts[0].Name, loadScripts[0].ScriptValue, ContextData, Key, userId);
                }
            }

            if (TempData.ContainsKey("ProcPage"))
            {
                TempData["ProcPage"] = cardPage;
            }
            else
            {
                TempData.Add("ProcPage", cardPage);
            }

            return View(cardPage);
        }

        public ActionResult Process(string ID, string Table, string Key)
        {
            serverPath = Server.MapPath("~/bin");
            if (Session["crmsession"] == null)
            {
                return RedirectToAction("Login", "Account");
            }

            string langid = Utility.GetLanguage(Session["crmsession"]);
            string userId = Utility.GetUserId(Session["crmsession"]);
            ContextData = new Dictionary<string, object>();

            MetaProcessPage cardPage = new MetaProcessPage();
            using (CRMDataContext dataContext = new CRMDataContext())
            {
                var appObjects = dataContext.GetAppObject(ID, "PROCESS", true);
                foreach (var appObject in appObjects)
                {
                    string formXml = appObject.AppMetaData;
                    cardPage = Utility.DeserializeString<MetaProcessPage>(formXml) as MetaProcessPage;
                }
            }

            foreach (MetaProcessFieldGroup fieldGroup in cardPage.FieldGroups)
            {
                foreach (MetaProcessField field in fieldGroup.Fields)
                {
                    ContextData.Add(field.Name, field.FieldValue);
                    //if (field.DataType == FieldDataType.Bool)
                    //{
                    //    if (field.FieldValue != null && field.FieldValue.ToString() == "true")
                    //    {
                    //        field.FieldValue = "on";
                    //    }
                    //}
                    //else
                    //{
                    //    field.FieldValue = "";
                    //}
                }
            }

            List<MetaScript> loadScripts = cardPage.GlobalScripts.Where(obj => (obj.Name.ToLower() == "pageload" && obj.Type == ScriptType.Server)).ToList();
            if (loadScripts.Count > 0)
            {
                RunProcessActionCode(ID, loadScripts[0].Name, loadScripts[0].ScriptValue, ContextData, Key, userId);
            }

            foreach (MetaProcessFieldGroup fieldGroup in cardPage.FieldGroups)
            {
                foreach (MetaProcessField field in fieldGroup.Fields)
                {
                    field.FieldValue = ContextData[field.Name];
                }
            }

            if (TempData.ContainsKey("ProcPage"))
            {
                TempData["ProcPage"] = cardPage;
            }
            else
            {
                TempData.Add("ProcPage", cardPage);
            }

            return View(cardPage);
        }

        public static void RunProcessActionCode(string ID, string methodName, string code, Dictionary<string, object> ContextData, string Key, string userId)
        {
            StringBuilder snippet = new StringBuilder();
            snippet.AppendLine("using System;");
            snippet.AppendLine("using System.Collections.Generic;");
            snippet.AppendLine("using System.Data;");
            snippet.AppendLine("using System.Dynamic;");
            snippet.AppendLine("using System.Web;");
            snippet.AppendLine("using Clirelmgt.Manager;");
            snippet.AppendLine("using Clirelmgt.Models;");
            snippet.AppendLine("using System.CodeDom.Compiler;");
            snippet.AppendLine("using Microsoft.CSharp;");
            snippet.AppendLine("using System.Text;");
            snippet.AppendLine("using System.Transactions;");
            snippet.AppendLine(string.Format("public class Cls{0}", ID));
            snippet.AppendLine("{");
            snippet.AppendLine(string.Format("    public static void {0}(Dictionary<string, object> ContextData, string Key)", methodName));
            snippet.AppendLine("    {");
            snippet.AppendLine("    try{");
            snippet.AppendLine("       using (TransactionScope tran = new TransactionScope()){");
            snippet.AppendLine(code.Replace(".INIT()", string.Format(".INIT(\"{0}\")", userId)));
            snippet.AppendLine("        tran.Complete();}");
            snippet.AppendLine("    }");
            snippet.AppendLine("    catch{throw;}");
            snippet.AppendLine("    }");
            snippet.AppendLine("}");

            CompilerResults cresult = CompileScript(snippet.ToString());
            if (!cresult.Errors.HasErrors)
            {
                var types = cresult.CompiledAssembly.GetTypes();
                if (types.Length > 0)
                {
                    List<object> args = new List<object>();
                    args.Add(ContextData);
                    args.Add(Key);
                    MethodInfo method = types[0].GetMethod(methodName);
                    method.Invoke(types[0], args.ToArray());
                }
            }
        }

        public static CompilerResults CompileScript(string source)
        {
            List<string> assemblies = new List<string>();
            assemblies.Add("System.dll");
            assemblies.Add("System.Data.dll");
            assemblies.Add("System.Core.dll");
            assemblies.Add("System.Transactions.dll");
            assemblies.Add("System.Data.Linq.dll");
            assemblies.Add("Microsoft.CSharp.dll");
            assemblies.Add(string.Format(@"{0}\Clirelmgt.dll", serverPath));
            CompilerParameters parms = new CompilerParameters(assemblies.ToArray());
            parms.GenerateExecutable = false;
            parms.GenerateInMemory = true;
            parms.IncludeDebugInformation = false;

            CodeDomProvider compiler = CSharpCodeProvider.CreateProvider("CSharp");

            return compiler.CompileAssemblyFromSource(parms, source);
        } 
    }
}
